/***************************************************************************//**
 * @file MSc_DataNode.h
 * @author  Marek M. Cel <marekcel@mscsim.org>
 *
 * @section LICENSE
 *
 * Copyright (C) 2014 Marek M. Cel
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/
#ifndef MSC_DATA_NODE_H
#define MSC_DATA_NODE_H

////////////////////////////////////////////////////////////////////////////////

#include <map>
#include <string>

#include <MSc_Defs.h>

////////////////////////////////////////////////////////////////////////////////

/** */
class MSc_DataNode
{
public:

    typedef std::map<std::string,MSc_DataNode*> DataNodes;

    /** Data type enum. */
    enum Type
    {
        Group  = 1,     ///< group node
        Bool   = 2,     ///< bool type
        Int    = 3,     ///< int type
        Long   = 4,     ///< long type
        Float  = 5,     ///< float type
        Double = 6      ///< double type
    };

    /** Constructor. */
    MSc_DataNode();

    /** Destructor. */
    virtual ~MSc_DataNode();

    /** @return MSCFDM_SUCCESS on success or MSCFDM_FAILURE on failure. */
    int addNode( std::string path, Type type );

    /** @return Data value on success or NaN on failure. */
    bool   getDatab() const;

    /** @return Data value on success or NaN on failure. */
    int    getDatai() const;

    /** @return Data value on success or NaN on failure. */
    long   getDatal() const;

    /** @return Data value on success or NaN on failure. */
    float  getDataf() const;

    /** @return Data value on success or NaN on failure. */
    double getDatad() const;

    /** */
    inline std::string getName() const
    {
        return m_name;
    }

    MSc_DataNode* getNode( std::string path );

    std::string getPath() const;

    /** @return Data node type. */
    inline Type getType() const
    {
        return m_type;
    }

    double getValue() const;

    /** @return MSCFDM_SUCCESS on success or MSCFDM_FAILURE on failure. */
    int setDatab( bool   value );

    /** @return MSCFDM_SUCCESS on success or MSCFDM_FAILURE on failure. */
    int setDatai( int    value );

    /** @return MSCFDM_SUCCESS on success or MSCFDM_FAILURE on failure. */
    int setDatal( long   value );

    /** @return MSCFDM_SUCCESS on success or MSCFDM_FAILURE on failure. */
    int setDataf( float  value );

    /** @return MSCFDM_SUCCESS on success or MSCFDM_FAILURE on failure. */
    int setDatad( double value );

private:

    /** Data variables union. */
    union Data
    {
        bool    bData;      ///< bool data
        int     iData;      ///< int data
        long    lData;      ///< long data
        float   fData;      ///< float data
        double  dData;      ///< double data
    };

    MSc_DataNode *m_parent; ///< parent node
    DataNodes m_children;   ///< node children

    std::string m_name;     ///< data node name

    Type m_type;    ///< type
    Data m_data;    ///< data

    /** Using this constructor is forbidden. */
    MSc_DataNode( const MSc_DataNode & ) {}

    /**
     * Breaks path string apart.
     * @param path path string to be broken
     * @param pathLead name of the first node in the path string
     * @param pathRest path relative to the first node in the unbroken path string
     */
    void breakPath( std::string path, std::string &pathLead, std::string &pathRest );

    /**
     * Creates node of the given name, type and parent.
     * @param name node name
     * @param type node type
     * @param parent node parent
     * @return data node pointer
     */
    MSc_DataNode* createNode( std::string name, Type type, MSc_DataNode *parent );

    /** */
    MSc_DataNode* findNode( std::string path );

    /** */
    void stripPathSlashes( std::string &path );
};

////////////////////////////////////////////////////////////////////////////////

#endif // MSC_DATA_NODE_H
